package com.arvin.router.core;


import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.ActivityCompat;
import android.text.TextUtils;
import android.text.style.TtsSpan;
import android.util.Log;

import com.arvin.router.core.exception.NoRouteFoundException;
import com.arvin.router.core.template.IRouteGroup;
import com.arvin.router.core.template.IRouteRoot;
import com.arvin.router.core.template.IService;
import com.arvin.router.core.utils.ClassUtils;
import com.arvin.router.model.RouteMeta;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

import javax.crypto.spec.PSource;

public class DNRouter {
    private static final String TAG = "DNRouter";
    private static final String ROUTE_ROOT_PACKAGE = "com.arvin.router.routes.";
    private static Application mContext;
    private static final String SDK_NAME = "DNRouter";
    private static final String SEPARATOR = "$$";
    private static final String SUFFIX_ROOT = "Root";

    private Handler mHandler;

    private DNRouter() {
        mHandler = new Handler(Looper.getMainLooper());
    }

    private static DNRouter instance;

    public static DNRouter getInstance() {
        synchronized (DNRouter.class) {
            if (instance == null) {
                instance = new DNRouter();
            }
        }
        return instance;
    }

    private static void loadInfo() throws Exception {
        Set<String> routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PACKAGE);
        for (String className : routerMap) {
            if (className.startsWith(ROUTE_ROOT_PACKAGE + "" + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                IRouteRoot iRouteRoot = (IRouteRoot) Class.forName(className).getConstructor().newInstance();
                iRouteRoot.loadInto(Warehouse.groupIndex);
            }
        }

        for (Map.Entry<String, Class<? extends IRouteGroup>> entry : Warehouse.groupIndex.entrySet()) {
            Log.e(TAG, "Root隐射表：[" + entry.getKey() + " : " + entry.getValue());
        }
    }

    public static void init(Application application) {
        mContext = application;
        try {
            loadInfo();
        } catch (Exception e) {
            e.printStackTrace();
            Log.e(TAG, "router 初始化失败");
        }
    }

    public PostCard build(String path, String group) {
        if (TextUtils.isEmpty(path)) {
            throw new RuntimeException("路由地址无效：");
        } else {
            return new PostCard(path, group);
        }
    }

    public PostCard build(String path) {
        if (TextUtils.isEmpty(path)) {
            throw new RuntimeException("路由地址无效");
        } else {
            return build(path, extractGroup(path));
        }
    }

    private String extractGroup(String path) {
        if (!path.startsWith("/")) {
            throw new RuntimeException(path + " : 不能提取group");
        }
        String defaultGroup = path.substring(1, path.indexOf("/", 1));
        if (TextUtils.isEmpty(defaultGroup)) {
            throw new RuntimeException(path + " : 不能提取group");
        } else {
            return defaultGroup;
        }
    }

    public Object navigation(Context context, final PostCard postCard, final int requestCode
    ) {
        try {
            prepareCard(postCard);
        } catch (NoRouteFoundException e) {
            e.printStackTrace();
            return null;
        }
        switch (postCard.getType()) {
            case ACTIVITY:
                final Context currentContext = null == mContext ? mContext : context;
                final Intent intent = new Intent(currentContext, postCard.getDestination());
                //intent.putExtras(postCard.getExtras());
                int flag = postCard.getflag();
                if (-1 != flag) {
                    intent.setFlags(flag);
                } else if (!(currentContext instanceof Activity)) {
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (requestCode > 0) {
                            ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postCard.getoptionsBundle());
                        } else {
                            ActivityCompat.startActivity(currentContext, intent, postCard.getoptionsBundle());
                        }
                        if (0 != postCard.getEnterAnim() || 0 != postCard.getExitAnim()
                                && currentContext instanceof Activity) {
                            ((Activity) currentContext).overridePendingTransition(postCard.getEnterAnim(), postCard.getExitAnim());
                        }
                    }
                });
                break;
            case SERVICE:
                return postCard.getService();
            default:
                break;
        }
        return null;
    }

    private void prepareCard(PostCard card) {
        RouteMeta routeMeta = Warehouse.routes.get(card.getPath());
        if (null == routeMeta) {
            Class<? extends IRouteGroup> groupMeta = Warehouse.groupIndex.get(card.getGroup());
            if (null == groupMeta) {
                throw new NoRouteFoundException("没找到对应路由 ： " + card.getGroup() + " " + card.getPath());
            }
            IRouteGroup iRouteGroupInstance;
            try {
                iRouteGroupInstance = groupMeta.getConstructor().newInstance();
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("路由分组银蛇表记录失败");
            }
            iRouteGroupInstance.loadInto(Warehouse.routes);
            Warehouse.groupIndex.remove(card.getGroup());
            prepareCard(card);
        } else {
            card.setDestination(routeMeta.getDestination());
            card.setType(routeMeta.getType());
            switch (routeMeta.getType()) {
                case SERVICE:
                    Class<?> destination = routeMeta.getDestination();
                    IService service = Warehouse.services.get(destination);
                    if (null == service) {
                        try {
                            service = (IService) destination.getConstructor().newInstance();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    card.setService(service);
                    break;
                default:
                    break;
            }
        }

    }


}
